package token

import (
	"encoding/json"
	"time"

	"gitee.com/liuxiaowei123/vblog-3/app/user"
	"gitee.com/liuxiaowei123/vblog-3/exception"
	"github.com/rs/xid"
)

type Token struct {
	// 该Token是颁发给哪个用户的
	UserId int `json:"user_id"`
	// 颁发给此用户的用户名
	UserName string `json:"username" gorm:"column:username"`
	// 颁发给用户的访问令牌(用户需要携带Token来访问接口)
	AccessToken string `json:"access_token"`
	// 过期时间(2h), 单位是秒
	AccessTokenExpiredAt int `json:"access_token_expired_at"`
	// 刷新Token
	RefreshToken string `json:"refresh_token"`
	// 刷新Token过期时间(7d)
	RefreshTokenExpiredAt int `json:"refresh_token_expired_at"`
	// 创建时间
	CreatedAt int64 `json:"created_at"`
	// 更新实现
	UpdatedAt int64 `json:"updated_at"`
	// 额外补充信息, gorm忽略处理，也就是无需入库；只要返回的token中有此字段就可以
	Role user.Role `gorm:"-"`
}

// 构建Token实例
func NewToken() *Token {
	return &Token{
		AccessToken:           xid.New().String(),
		AccessTokenExpiredAt:  7200,
		RefreshToken:          xid.New().String(),
		RefreshTokenExpiredAt: 3600 * 24 * 7,
		CreatedAt:             time.Now().Unix(),
	}
}

// 把结构体Token转换成Json格式的字符串
func (tk *Token) String() string {
	js, _ := json.Marshal(tk)
	return string(js)
}

// 扩展Token方法，计算出token过期时间
func (tk *Token) ExpiredTime() time.Time {
	// time.Unix函数用于将给定的秒数和纳秒数转换为time.Time类型的时间
	t := time.Unix(tk.CreatedAt, 0)
	// 显式地将tk.AccessTokenExpiredAt从秒转换为time.Duration类型的时间间隔（表示为纳秒）,然后将其添加到t上
	return t.Add(time.Duration(tk.AccessTokenExpiredAt) * time.Second)
	// 这种写法没有显式地指定时间单位，因此time.Duration类型的时间间隔默认使用纳秒为单位。
	// return t.Add(time.Duration(tk.AccessTokenExpiredAt))
}

// 扩展Token方法，判断token是否过期
func (tk *Token) IsExpiredTime() error {
	// 当前时间token过期时间
	d := time.Since(tk.ExpiredTime())
	t := d.Seconds()
	if t > 0 {
		return exception.NewTokenExpired("token %s 已经过期", tk.AccessToken)
	}
	return nil
}
